home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Libraries / SAT 2.1.2 / Misc / TransSkel.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-08  |  51.0 KB  |  1,954 lines  |  [TEXT/KAHL]

  1. /*
  2.     TransSkel - Transportable application skeleton
  3.     TransSkel is public domain.
  4.     Version 2.6 of 8/17/90
  5.  
  6.     This version by:
  7.             Bob Schumaker and Dan Hite
  8.             The AMIX Corporation
  9.             2345 Yale Street
  10.             Palo Alto, CA 94306
  11.  
  12.     UUCP:    {sun, uunet}!markets![bob,dan]
  13.     ARPA:    [bob,dan]@amix.com
  14.  
  15.      Originally written by:
  16.             Paul DuBois
  17.             Wisconsin Regional Primate Research Center
  18.             1220 Capital Court
  19.             Madison WI  53706  USA
  20.  
  21.     UUCP:    {allegra,ihnp4,seismo}!uwvax!uwmacc!dubois
  22.     ARPA:    dubois@unix.macc.wisc.edu
  23.             dubois@rhesus.primate.wisc.edu
  24. */
  25.  
  26. /*
  27.     The following symbol controls support for dialogs.
  28.     Changing #define to #undef disables the support.
  29. */
  30.  
  31. #include "TransSkel.h"
  32. //#include "TransSkull.h"
  33. #ifdef applec
  34. #include <Desk.h>
  35. #include <DiskInit.h>
  36. #include <Fonts.h>
  37. #include <Memory.h>
  38. #include <OSEvents.h>
  39. #include <Resources.h>
  40. #include <Script.h>
  41. #include <ToolUtils.h>
  42. #else
  43. #define curSysEnvVers    1
  44. #define zoomDocProc 8
  45. #define    DragGrayRgnProcPtr    ProcPtr
  46. #endif
  47.  
  48. /*
  49.     New(TypeName) returns handle to new object, for any TypeName.
  50.     If there is insufficient memory, the result is nil.
  51. */
  52.  
  53. #define    New(x)    (x **) NewHandle (sizeof (x))
  54.  
  55.  
  56. /*
  57.     Window and Menu handler types, constants, variables.
  58.  
  59.     whList and mhList are the lists of window and menu handlers.
  60.     whClobOnRmve and mhClobOnRmve are true if the handler disposal proc
  61.     is to be called when a handler is removed.  They are temporarily set
  62.     false when handlers are installed for windows or menus that already
  63.     have handlers - the old handler is removed WITHOUT calling the
  64.     disposal proc.
  65.  
  66.     Default lower limits on window sizing of 80 pixels both directions is
  67.     sufficient to allow text windows room to draw a grow box and scroll
  68.     bars without having the thumb and arrows overlap.  These values may
  69.     be changed if such a constraint is undesirable with SkelGrowBounds.
  70.     Default upper limits are for the Macintosh, not the Lisa, but are set
  71.     per machine in SkelInit.
  72. */
  73.  
  74. typedef struct WHandler
  75. {
  76.     WindowPtr    whWind;                        /* window/dialog to be handled    */
  77. #ifdef applec
  78.     void    (*whClobber)(void);                /* data structure disposal proc */
  79.     void    (*whMouse)(Point, long, short);    /* mouse-click handler proc        */
  80.     void    (*whKey)(char, unsigned char, short);    /* key-click handler proc */
  81.     void    (*whUpdate)(Boolean, short);    /* update handler proc            */
  82.     void    (*whActivate)(Boolean);            /* activate event handler proc    */
  83.     void    (*whClose)(void);                /* close "event" handler proc    */
  84.     void    (*whIdle)(void);                /* main loop proc                */
  85. #ifdef    supportDialogs
  86.     Boolean    (*whEvent)(short *, EventRecord *);/* event hook                */
  87.     Boolean    (*whCheck)(short);                /* hit notify                     */
  88. #endif
  89. #else
  90.     void    (*whClobber)();        /* data structure disposal proc */
  91.     void    (*whMouse)();        /* mouse-click handler proc        */
  92.     void    (*whKey)();            /* key-click handler proc        */
  93.     void    (*whUpdate)();        /* update handler proc            */
  94.     void    (*whActivate)();    /* activate event handler proc    */
  95.     void    (*whClose)();        /* close "event" handler proc    */
  96.     void    (*whIdle)();        /* main loop proc                */
  97. #ifdef    supportDialogs
  98.     Boolean    (*whEvent)();        /* event hook                    */
  99.     Boolean    (*whCheck)();        /* hit notify                    */
  100. #endif
  101. #endif
  102.     Rect        whGrow;            /* limits on window sizing            */
  103.     RgnHandle    whCursorRgn;    /* cursor region when front window    */
  104.     CursHandle    whCursor;        /* cursor to show while in region    */
  105.     long        userReference;    /* a user specified longword        */
  106.     short        whSizedMods;    /* keys held down while window was resized */
  107. #ifdef supportDialogs
  108.     short        whItemHit;        /* the last item hit in this dialog */
  109.     Boolean        whModal;        /* treat this as a modal dialog?    */
  110. #endif
  111.     Boolean        whCanGrow;        /* this window *can* be grown!!        */
  112.     Boolean        whSized;        /* true = window was resized        */
  113.     Boolean        whFrontOnly;    /* true = idle only when active        */
  114.     Boolean        whHaveCursor;    /* cursor associated with this window */
  115.     struct WHandler    **whNext;    /* next window handler                */
  116. } WHandler;
  117.  
  118. static WHandler    **whList = nil;
  119. static Boolean    whClobOnRmve = true;
  120. static Rect        growRect;
  121. static short mBarHeight;    /* menu bar height.  All window sizing
  122.                               code takes this into account */
  123.  
  124. static RgnHandle cursorRgn;        /* use this to manage the cursor */
  125. static RgnHandle screensRgn;
  126. static Boolean useWaitNextEvent;
  127. static SysEnvRec skelEnvRec;
  128.  
  129. typedef struct MHandler
  130. {
  131.     short            mhID;                        /* menu id                     */
  132. #ifdef applec
  133.     void            (*mhSelect)(short);            /* item selection handler proc */
  134.     void            (*mhClobber)(MenuHandle);    /* menu disposal handler proc  */
  135. #else
  136.     void            (*mhSelect)();            /* item selection handler proc */
  137.     void            (*mhClobber)();            /* menu disposal handler proc  */
  138. #endif
  139.     struct MHandler    **mhNext;                    /* next menu handler           */
  140. } MHandler;
  141.  
  142.  
  143. static MHandler    **mhList = nil;            /* list of menu handlers */
  144. static Boolean    mhClobOnRmve = true;
  145.  
  146.  
  147. /*
  148.     Variables for default Apple menu handler.  appleID is set to 1 if
  149.     SkelApple is called and is the id of the Apple menu, appleAboutProc
  150.     is the procedure to execute if there is an About... item and it's
  151.     chosen from the Apple menu.  If doAbout is true, then the menu
  152.     contains the About... item, otherwise it's just desk accessories.
  153. */
  154.  
  155. static MenuHandle    appleMenu;
  156. static short        appleID = 0;
  157. #ifdef applec
  158. static void            (*appleAboutProc)(void) = nil;
  159. static void            (*appleHelpProc)(void) = nil;
  160. #else
  161. static void            (*appleAboutProc)() = nil;
  162. static void            (*appleHelpProc)() = nil;
  163. #endif
  164. static Boolean        doAbout = false;
  165. static Boolean        doHelp = false;
  166. /*
  167.     Miscellaneous
  168.  
  169.     screenPort points to the window manager port.
  170.     
  171.     doneFlag determines when SkelMain returns.  It is set by calling
  172.     SkelWhoa(), which the host does to request a halt.
  173.  
  174.     pBkgnd points to a background procedure, to be run during event
  175.     processing.  Set it with SkelBackground.  If nil, there's no
  176.     procedure.
  177.  
  178.     pEvent points to an event-inspecting hook, to be run whenever an
  179.     event occurs.  Set it with SkelEventHook.  If nil, there's no
  180.     procedure.
  181.  
  182.     eventMask controls the event types requested in the GetNextEvent
  183.     call in SkelMain.
  184.  
  185.     diskInitPt is the location at which the disk initialization dialog
  186.     appears, if an uninitialized disk is inserted.
  187. */
  188.  
  189. static GrafPtr    screenPort;
  190. static Boolean    doneFlag = false;
  191.  
  192. #ifdef applec
  193. static Boolean    (*pEvent)(EventRecord *) = nil;
  194. static void        (*pBkgnd)(void) = nil;
  195. #else
  196. static Boolean    (*pEvent)() = nil;
  197. static void        (*pBkgnd)() = nil;
  198. #endif
  199. static long     pFGTime = 6L;            /* tenth of a second */
  200. static long        pBGTime = 300L;            /* 5 seconds */
  201. static Boolean    fgApp = true;            /* handle suspend/resume events */
  202.  
  203. static short    eventMask = everyEvent ^ keyUpMask;
  204. static Point    diskInitPt = { /* v = */ 120, /* h = */ 100 };
  205.  
  206. #ifdef applec
  207. static void (*pScrapConvert)(Boolean) = nil;
  208. static void (*pSuspendResume)(Boolean) = nil;
  209. static void (*pZoomProc)(WindowPtr, short, short, Boolean) = nil;
  210. static void (*pNetworkProc)(EventRecord *) = nil;
  211. static void (*pChildDied)(EventRecord *) = nil;
  212. static void (*pHandleApp4)(EventRecord *) = nil;
  213. #else
  214. static void (*pScrapConvert)() = nil;
  215. static void (*pSuspendResume)() = nil;
  216. static void (*pZoomProc)() = nil;
  217. static void (*pNetworkProc)() = nil;
  218. static void (*pChildDied)() = nil;
  219. static void (*pHandleApp4)() = nil;
  220. #endif
  221.  
  222. #ifdef    supportDialogs
  223.  
  224. /*
  225.     Events that are passed to dialogs.  Others are ignored.
  226.     Standard mask passes , mousedown, keydown, autokey, update,
  227.     activate and null events.  Null events are controlled by bit 0.
  228. */
  229.  
  230. static short    dlogEventMask = 0x16b;
  231.  
  232. #endif
  233.  
  234. /* -------------------------------------------------------------------- */
  235. /*                        Internal (private) Routines                        */
  236. /* -------------------------------------------------------------------- */
  237.  
  238. /*
  239.     Get handler associated with user or dialog window.
  240.     Return nil if window doesn't belong to any known handler.
  241.     This routine is absolutely fundamental to TransSkel.
  242. */
  243.  
  244. static WHandler    **GetWDHandler(WindowPtr theWind)
  245. {
  246.     register WHandler    **h;
  247.  
  248.     if (theWind) {
  249.         for (h = whList; h != nil; h = (**h).whNext) {
  250.             if ((**h).whWind == theWind) {
  251.                 return (h);
  252.             }
  253.         }
  254.     }
  255.     return (nil);
  256. }
  257.  
  258.  
  259. /*
  260.     Get handler associated with user window.
  261.     Return nil if window doesn't belong to any known handler.
  262.     The order of the two tests is critical:  theWind might be nil.
  263. */
  264.  
  265. static WHandler    **GetWHandler(WindowPtr theWind)
  266. {
  267.     register WHandler    **h;
  268.  
  269.     if ((h = GetWDHandler (theWind)) != nil
  270.         && ((WindowPeek) theWind)->windowKind != dialogKind) {
  271.         return (h);
  272.     }
  273.     return (nil);
  274. }
  275.  
  276. #ifdef    supportDialogs
  277.  
  278. /*
  279.     Get handler associated with dialog window.
  280.     Return nil if window doesn't belong to any known handler.
  281.     The order of the two tests is critical:  theDialog might be nil.
  282. */
  283.  
  284. static WHandler    **GetDHandler(DialogPtr theDialog)
  285. {
  286.     register WHandler    **h;
  287.  
  288.     if ((h = GetWDHandler (theDialog)) != nil
  289.         && ((WindowPeek) theDialog)->windowKind == dialogKind)
  290.     {
  291.             return (h);
  292.     }
  293.     return (nil);
  294. }
  295.  
  296. #endif
  297.  
  298. static GetPortBounds(WindowPeek winPeek, Rect *bounds)
  299. {
  300.     if ((winPeek->port.portBits.rowBytes & 0xC000) == 0xC000) {
  301.         /* it's a color window!! */
  302.         *bounds = (**((CGrafPtr)(&winPeek->port))->portPixMap).bounds;
  303.     }
  304.     else {
  305.         *bounds = winPeek->port.portBits.bounds;
  306.     }
  307. }
  308.  
  309. static WHandler **SkelNullHandler(WindowPtr theWin)
  310. {
  311.     register WHandler    **h;
  312.     if (h = New (WHandler)) 
  313.     {
  314.         (**h).whWind = theWin;
  315.         (**h).whMouse = nil;
  316.         (**h).whKey = nil;
  317.         (**h).whUpdate = nil;
  318.         (**h).whActivate = nil;
  319.         (**h).whClose = nil;
  320.         (**h).whClobber = nil;
  321.         (**h).whIdle = nil;
  322.         (**h).whFrontOnly = true;
  323.         (**h).whSized = false;
  324.         (**h).whSizedMods = 0;
  325.         (**h).whGrow = growRect;
  326.         (**h).whCanGrow = true;
  327.         (**h).whHaveCursor = false;
  328.         (**h).whCursorRgn = (RgnHandle) 0;
  329.         (**h).whCursor = (CursHandle) 0;
  330.         (**h).userReference = 0L;
  331. #ifdef supportDialogs
  332.         (**h).whEvent = nil;
  333.         (**h).whCheck = nil;
  334.         (**h).whItemHit = 0;
  335.         (**h).whModal = false;
  336. #endif
  337.         /* add this into the window list! */
  338.         (**h).whNext = whList;
  339.         whList = h;
  340.     }
  341.     return (h);
  342. }
  343.  
  344. void SkelDragWindow (WindowPtr theWin, Point pt, short mods, Rect *bounds)
  345. {
  346.     if (!(mods & cmdKey)) {
  347.         SelectWindow (theWin);
  348.         SetPort (theWin);
  349.         if (!StillDown ())
  350.             return;
  351.     }
  352.     DragWindow (theWin, pt, bounds);
  353. }
  354.  
  355. /*
  356.     Remove a menu handler.  This calls the handler's disposal routine
  357.     and then takes the handler out of the handler list and disposes
  358.     of it.
  359.  
  360.     Note that the menu MUST be deleted from the menu bar before calling
  361.     the clobber proc, because the menu bar will end up filled with
  362.     garbage if the menu was allocated with NewMenu (see discussion of
  363.     DisposeMenu in Menu Manager section of Inside Macintosh).
  364.  
  365.     The menu bar is only redrawn if redrawBar is true--this removes
  366.     the flicker from the menu bar when the application terminates.
  367. */
  368.  
  369. static void RemoveMenu(MenuHandle theMenu, Boolean redrawBar)
  370. {
  371.     register short        mID;
  372.     register MHandler    **h, **h2;
  373. #ifdef applec
  374.     register void        (*p)(MenuHandle);
  375. #else
  376.     register void        (*p)();
  377. #endif
  378.  
  379.     mID = (**theMenu).menuID;
  380.     /* if list empty, ignore */
  381.     if (mhList != nil) {
  382.         /* is it the first element? */
  383.         if ((**mhList).mhID == mID) {
  384.             h2 = mhList;
  385.             mhList = (**mhList).mhNext;
  386.         }
  387.         else {
  388.             for (h = mhList; h != nil; h = h2) {
  389.                 h2 = (**h).mhNext;
  390.                 if (h2 == nil)
  391.                     return;                        /* menu not in list! */
  392.                 if ((**h2).mhID == mID) {
  393.                     /* found it */
  394.                     (**h).mhNext = (**h2).mhNext;
  395.                     break;
  396.                 }
  397.             }
  398.         }
  399.         DeleteMenu (mID);
  400.         if (redrawBar) {
  401.             DrawMenuBar ();
  402.         }
  403.         if (mhClobOnRmve && (p = (**h2).mhClobber) != nil) {
  404.             (*p) (theMenu);                        /* call disposal routine */
  405.         }
  406.         DisposHandle ((Handle) h2);                /* get rid of handler record */
  407.     }
  408. }
  409.  
  410. /*
  411.     General menu-handler.  Just passes selection to the handler's
  412.     select routine.  If the select routine is nil, selecting items from
  413.     the menu is a nop.
  414. */
  415.  
  416. static void DoMenuCommand(long command)
  417. {
  418.     register short        menu;
  419.     register short        item;
  420.     register MHandler    **mh;
  421. #ifdef applec
  422.     register void        (*p)(short);
  423. #else
  424.     register void        (*p)();
  425. #endif
  426.  
  427.     menu = HiWord (command);
  428.     item = LoWord (command);
  429.     for (mh = mhList; mh != nil; mh = (**mh).mhNext) {
  430.         if ((menu == (**mh).mhID) && ((p = (**mh).mhSelect) != nil)) {
  431.             (*p) (item);
  432.             break;
  433.         }
  434.     }
  435.     HiliteMenu (0);        /* command done, turn off menu hiliting */
  436. }
  437.  
  438.  
  439. /*
  440.     Apple menu handler
  441.     
  442.     DoAppleItem:  If the first item was chosen, and there's an "About..."
  443.     item, call the procedure associated with it (if not nil).  If there
  444.     is no "About..." item or the item was not the first one, then open
  445.     the associated desk accessory.  The port is saved and restored
  446.     because OpenDeskAcc does not always preserve it correctly.
  447.     
  448.     DoAppleClobber disposes of the Apple menu.
  449. */
  450.  
  451. static void DoAppleItem(short item)
  452. {
  453.     GrafPtr        curPort;
  454.     Str255        str;
  455.  
  456.     if (doAbout && item == 1)
  457.     {
  458.         if (appleAboutProc != nil)
  459.             (*appleAboutProc) ();
  460.     }
  461.     else 
  462.         if (doHelp && item == 2) 
  463.         {
  464.             if (appleHelpProc != nil) 
  465.             {
  466.                 (*appleHelpProc) ();
  467.             }
  468.         }
  469.         else
  470.         {
  471.             GetPort (&curPort);
  472.             GetItem (appleMenu, item, str);        /* get DA name */
  473.             (void) OpenDeskAcc (str);            /* open it */
  474.             SetPort (curPort);
  475.         }
  476. }
  477.  
  478. static void DoAppleClobber ()
  479. {
  480.     DisposeMenu (appleMenu);
  481. }
  482.  
  483.  
  484. /* -------------------------------------------------------------------- */
  485. /*                        Window-handler routing routines                    */
  486. /*                                                                        */
  487. /*    Each routine sets the port to the handler's window before executing    */
  488. /*    the handler procedure.                                                */
  489. /* -------------------------------------------------------------------- */
  490.  
  491.  
  492. /*
  493.     Pass local mouse coordinates, click time, and the modifiers flag
  494.     word to the handler.
  495. */
  496.  
  497. static void DoMouse(WHandler **h, EventRecord *theEvent)
  498. {
  499. #ifdef applec
  500.     register void    (*p)(Point, long, short);
  501. #else
  502.     register void    (*p)();
  503. #endif
  504.     Point            thePt;
  505.  
  506.     if (h != nil) {
  507.         SetPort ((**h).whWind);
  508.         if ((p = (**h).whMouse) != nil) {
  509.             thePt = theEvent->where;    /* make local copy */
  510.             GlobalToLocal (&thePt);
  511.             (*p) (thePt, theEvent->when, theEvent->modifiers);
  512.         }
  513.     }
  514. }
  515.  
  516.  
  517. /*
  518.     Pass the character and the modifiers flag word to the handler.
  519. */
  520.  
  521. static void DoKey(WHandler **h, char ch, unsigned char code, short mods)
  522. {
  523. #ifdef applec
  524.     register void (*p)(char, unsigned char, short);
  525. #else
  526.     register void (*p)();
  527. #endif
  528.     if (h != nil) {
  529.         SetPort ((**h).whWind);
  530.         if ((p = (**h).whKey) != nil)
  531.             (*p) (ch, code, mods);
  532.     }
  533. }
  534.  
  535.  
  536. /*
  537.     Call the window updating procedure, passing to it an indicator whether
  538.     the window has been resized or not.  Then clear the flag, assuming
  539.     the update proc took whatever action was necessary to respond to
  540.     resizing.
  541.  
  542.     If the handler doesn't have any update proc, the Begin/EndUpdate
  543.     stuff is still done, to clear the update region.  Otherwise the
  544.     Window Manager will keep generating update events for the window,
  545.     stalling updates of other windows.
  546.  
  547.     Make sure to save and restore the port, as it's not always the
  548.     active window that is updated.
  549. */
  550.  
  551. static void DoUpdate (WHandler    **h)
  552. {
  553. #ifdef applec
  554.     register void        (*p)(Boolean, short);
  555. #else
  556.     register void        (*p)();
  557. #endif
  558.     register GrafPtr    updPort;
  559.     GrafPtr                tmpPort;
  560.  
  561.     if (h != nil) {
  562.         GetPort (&tmpPort);
  563.         SetPort (updPort = (**h).whWind);
  564.         BeginUpdate (updPort);
  565.         if ((p = (**h).whUpdate) != nil) {
  566.             (*p) ((**h).whSized, (**h).whSizedMods);
  567.             (**h).whSized = false;
  568.             (**h).whSizedMods = 0;
  569.         }
  570.         EndUpdate (updPort);
  571.         SetPort (tmpPort);
  572.     }
  573. }
  574.  
  575.  
  576. /*
  577.     Pass activate/deactivate notification to handler.
  578. */
  579.  
  580. static void DoActivate(WindowPtr theWin, Boolean active)
  581. {
  582. #ifdef applec
  583.     register void (*p)(Boolean);
  584. #else
  585.     register void (*p)();
  586. #endif
  587.     WHandler    **h;
  588.  
  589.     if ((h = GetWDHandler (theWin)) != nil) {
  590.         SetPort ((**h).whWind);
  591.         if ((p = (**h).whActivate) != nil) {
  592.             (*p) (active);
  593.         }
  594.         /* reset the cursor region */
  595.         if (active) {
  596.             SetEmptyRgn (cursorRgn);
  597.         }
  598.     }
  599. }
  600.  
  601.  
  602. /*
  603.     Execute a window handler's close proc.  This may be used by handlers
  604.     for temp windows that want to remove themselves when the window
  605.     is closed:  they can call SkelRmveWind to dispose of the window
  606.     and remove the handler from the window handler list.  Thus, windows
  607.     may be dynamically created and destroyed without filling up the
  608.     handler list with a bunch of invalid handlers.
  609.     
  610.     If the handler doesn't have a close proc, just hide the window.
  611.     The host should provide some way of reopening the window (perhaps
  612.     a menu selection).  Otherwise the window will be lost from user
  613.     control if it is hidden, since it won't receive user events.
  614.  
  615.     The port is set to the window manager port after calling the
  616.     handler proc, to avoid a dangling port.
  617.  
  618.     This is called both for regular and dialog windows.
  619. */
  620.  
  621. static void DoClose (WHandler **h)
  622. {
  623. #ifdef applec
  624.     register void        (*p)(void);
  625. #else
  626.     register void        (*p)();
  627. #endif
  628.     GrafPtr savePort;
  629.  
  630.     if (h != nil) {
  631.         if ((p = (**h).whClose) != nil) {
  632.             GetPort (&savePort);
  633.             SetPort ((**h).whWind);
  634.             (*p) ();
  635.             SetPort (savePort);
  636.         }
  637.         else {
  638.             HideWindow ((**h).whWind);
  639.         }
  640.     }
  641. }
  642.  
  643.  
  644. /*
  645.     Execute a window handler's clobber proc.
  646.  
  647.     The port is set to the window manager port after calling the
  648.     handler proc, to avoid a dangling port.
  649.  
  650.     This is called both for regular and dialog windows.
  651. */
  652.  
  653. static void DoClobber (WHandler **h)
  654. {
  655. #ifdef applec
  656.     register void (*p)(void);
  657. #else
  658.     register void (*p)();
  659. #endif
  660.     GrafPtr    tmpPort;
  661.  
  662.     GetPort (&tmpPort);
  663.     SetPort ((**h).whWind);
  664.     if ((p = (**h).whClobber) != nil)
  665.         (*p) ();
  666.     SetPort (tmpPort);
  667. }
  668.  
  669.  
  670. /*
  671.     Execute handler's idle proc.
  672.  
  673.     Make sure to save and restore the port, since idle procs may be
  674.     called for any window, not just the active one.
  675. */
  676.  
  677. static void DoIdle (WHandler **h)
  678. {
  679. #ifdef applec
  680.     register void (*p)(void);
  681. #else
  682.     register void (*p)();
  683. #endif
  684.     GrafPtr            tmpPort;
  685.  
  686.     if (h != nil) 
  687.     {
  688.         if (!useWaitNextEvent) 
  689.         {
  690.             SystemTask ();
  691.         }
  692.         GetPort (&tmpPort);
  693.         SetPort ((**h).whWind);
  694.         if ((p = (**h).whIdle) != nil)
  695.             (*p) ();
  696.         SetPort (tmpPort);
  697.     }
  698. }
  699.  
  700.  
  701. #ifdef    supportDialogs
  702.  
  703. /* -------------------------------------------------------------------- */
  704. /*                            Dialog-handling routines                    */
  705. /* -------------------------------------------------------------------- */
  706.  
  707.  
  708. /*
  709.     Handle event if it's for a dialog.  The event must be one of
  710.     those that is passed to dialogs according to dlogEventMask.
  711.     This mask can be set so that disk-inserts, for instance, don't
  712.     get eaten up.
  713. */
  714.  
  715. static Boolean DoDialog (EventRecord *evt)
  716. {
  717.     register WHandler    **dh;
  718.     DialogPtr            theDialog;
  719.     register short        what;
  720.     short                item;
  721.     Boolean                handledIt = false;
  722. #ifdef applec
  723.     Boolean                (*pKeys)(short *, EventRecord *);
  724. #else
  725.     Boolean                (*pKeys)();
  726. #endif
  727.  
  728.     theDialog = (DialogPtr) FrontWindow ();
  729.     if ((dh = GetDHandler (theDialog)) != nil) {
  730. #ifdef applec
  731.         pKeys = (Boolean (*)(short *, EventRecord *)) (**dh).whKey;
  732. #else
  733.         pKeys = (Boolean (*)()) (**dh).whKey;
  734. #endif
  735.     }
  736.     else {
  737.         pKeys = nil;
  738.     }
  739.     what = evt->what;
  740. /* handle command keys before they get to IsDialogEvent */
  741.     if ((what == keyDown || what == autoKey) && (evt->modifiers & cmdKey)) {
  742.         if (!(pKeys && (handledIt = (*pKeys) (&item, evt)))) {
  743.             if (!(dh && (**dh).whModal)) {
  744.                 DoMenuCommand (MenuKey (evt->message & charCodeMask));
  745.             }
  746.             return (true);
  747.         }
  748.     }
  749.     else if (what == app4Evt || what == updateEvt) {
  750.         /* do multifinder events, updates are handled in the main loop */
  751.         if (dh && (**dh).whEvent) {
  752.             handledIt = (*(**dh).whEvent)(&item, evt);
  753.         }
  754.         return (handledIt);               /* main section handles these */
  755.     }
  756.     else if (((1 << what) & dlogEventMask) && IsDialogEvent (evt)) {
  757.         item = 0;
  758.         switch (what) {
  759.             case keyDown:
  760.             case autoKey:
  761.                 if (!(pKeys && (handledIt = (*pKeys) (&item, evt)))) {
  762.                     handledIt = DialogSelect (evt, &theDialog, &item);
  763.                 }
  764.                 break;
  765.             case activateEvt:                        /* if activate */
  766.                 theDialog = (DialogPtr) evt->message;
  767.                 dh = GetDHandler ((WindowPtr) theDialog);
  768.                 if ((evt->modifiers & activeFlag)    /* and coming active */
  769.                     && ((WindowPeek) theDialog)->windowKind == dialogKind) {
  770.                     SetPort ((GrafPtr) theDialog);
  771.                 }
  772.             /* fall through */
  773.             default:
  774.                 if (!(dh && (**dh).whEvent &&
  775.                         (handledIt = (*(**dh).whEvent)(&item, evt))    )) {
  776.                     handledIt = DialogSelect (evt, &theDialog, &item);
  777.                 }
  778.                 break;
  779.         }
  780.         if ((dh = GetDHandler ((WindowPtr) theDialog)) != nil) {
  781.             (**dh).whItemHit = item;
  782.             /* if this is a modal dialog, whCheck will be called elsewhere */
  783.             if ((**dh).whCheck && !(**dh).whModal) {
  784.                 (*(**dh).whCheck) (item);
  785.             }
  786.         }
  787.     }
  788.     return (handledIt);
  789. }
  790.  
  791. #endif
  792.  
  793. /* -------------------------------------------------------------------- */
  794. /*                            Event-handling routines                        */
  795. /* -------------------------------------------------------------------- */
  796.  
  797.  
  798. static void SkelCheckCursor(WHandler **wh, Point mouse, RgnHandle region)
  799. {
  800.     Point pt;
  801.     RgnHandle arrowRgn, localRgn;
  802.  
  803.     if (wh && (**wh).whHaveCursor) 
  804.     {
  805.         arrowRgn = NewRgn ();
  806.         localRgn = NewRgn ();
  807.         CopyRgn ((**wh).whCursorRgn, localRgn);
  808.         CopyRgn (screensRgn, arrowRgn);
  809.         SetPt (&pt, 0, 0);
  810.         SetPort ((**wh).whWind);
  811.         LocalToGlobal (&pt);
  812.         OffsetRgn (localRgn, pt.h, pt.v);
  813.         DiffRgn (arrowRgn, localRgn, arrowRgn);
  814.  
  815.         if (PtInRgn (mouse, localRgn)) 
  816.         {
  817.             SetCursor (*(**wh).whCursor);
  818.             CopyRgn (localRgn, region);
  819.         }
  820.         else {
  821.             InitCursor ();
  822.             CopyRgn (arrowRgn, region);
  823.         }
  824.         DisposeRgn (localRgn);
  825.         DisposeRgn (arrowRgn);
  826.     }
  827.     else {
  828.         InitCursor ();
  829.         CopyRgn (screensRgn, region);
  830.     }
  831. }
  832.  
  833. /*
  834.     Have either zoomed a window or sized it manually.  Invalidate
  835.     it to force an update and set the 'resized' flag in the window
  836.     handler true.  The port is assumed to be set to the port that changed
  837.     size.
  838. */
  839.  
  840. static void TriggerUpdate(WHandler **h, GrafPtr grownPort, short mods)
  841. {
  842.     GrafPtr savePort;
  843.  
  844.     GetPort (&savePort);
  845.     SetPort (grownPort);
  846.     InvalRect (&grownPort->portRect);
  847.     if (h != nil) {
  848.         (**h).whSized = true;
  849.         (**h).whSizedMods = mods;
  850.         if ((**h).whHaveCursor && grownPort == FrontWindow ()) 
  851.         {
  852.             SetEmptyRgn (cursorRgn);
  853.         }
  854.     }
  855.     SetPort (savePort);
  856. }
  857.  
  858. /*
  859.     Size a window.  If the window has a handler, use the grow limits
  860.     in the handler record, otherwise use the defaults.
  861.  
  862.     The portRect is invalidated to force an update event.  (The port
  863.     must be set first, as it could be pointing anywhere.)  The handler's
  864.     update procedure should check the parameter passed to it to check
  865.     whether the window has changed size, if it needs to adjust itself to
  866.     the new size.  THIS IS A CONVENTION.  Update procs must notice grow
  867.     "events", there is no procedure specifically for such events.
  868.     
  869.     The clipping rectangle is not reset.  If the host application
  870.     keeps the clipping set equal to the portRect or something similar,
  871.     then it will have to arrange to treat window growing with more
  872.     care.
  873.  
  874.     Since the grow region of only the active window may be clicked,
  875.     it should not be necessary to set the port.
  876. */
  877.  
  878. static void DoGrow(WHandler **h, GrafPtr thePort, Point startPt, short mods)
  879. {
  880.     Rect                r;
  881.     register long        growRes;
  882.  
  883.     r = (**h).whGrow;
  884.     /* grow result non-zero if size change    */
  885.     if (growRes = GrowWindow (thePort, startPt, &r)) {
  886.         SizeWindow (thePort, LoWord (growRes), HiWord (growRes), false);
  887.         TriggerUpdate (h, thePort, mods);
  888.     }
  889. }
  890.  
  891.  
  892. /*
  893.     Zoom the current window.  Very similar to DoGrow
  894.  
  895.     Since the zoombox of only the active window may be clicked,
  896.     it should not be necessary to set the port.
  897. */
  898.  
  899. static void DoZoom(WHandler **h, GrafPtr zoomPort, short partCode, short mods)
  900. {
  901.     if (pZoomProc) 
  902.     {
  903.         /* for a custom zoom proc, allow the user to modify the behaviour */
  904.         (*pZoomProc) (zoomPort, partCode, mods, false);
  905.     }
  906.     else 
  907.         {
  908.             ZoomWindow (zoomPort, partCode, false);
  909.     }
  910.     TriggerUpdate (h, zoomPort, mods);
  911. }
  912.  
  913. /*
  914.     General event handler
  915. */
  916.  
  917. static void DoEvent (EventRecord *theEvt)
  918. {
  919.     register EventRecord    *theEvent;
  920.     Point                    evtPt;
  921.     GrafPtr                    evtPort;
  922.     register short            evtPart;
  923.     register char            evtChar;
  924.     register unsigned char    evtCode;
  925.     register short            evtMods = 0;
  926.     register WHandler        **h, **t;
  927.     Rect                    r;
  928.     WindowPtr                frontWindow = FrontWindow ();
  929.  
  930.     theEvent = theEvt;
  931.  
  932. #ifdef    supportDialogs
  933.     if(DoDialog (theEvent))
  934.         return;
  935. #endif
  936.  
  937.     evtPt = theEvent->where;
  938.     evtMods = theEvent->modifiers;
  939.  
  940.     switch (theEvent->what) 
  941.     {
  942.         case app4Evt:        /* multifinder event */
  943.             {
  944.                 short flag = ((theEvent->message >> 24) & 0xff);
  945.                 if (flag == 0x01) {
  946.                     fgApp = ((theEvent->message & 0x01) != 0);
  947.                     DoActivate (frontWindow, fgApp);
  948.                     /* does the app want to know about suspend/resume? */
  949.                     if (pSuspendResume) {
  950.                         (*pSuspendResume)(fgApp);
  951.                     }
  952.                     /* should we convert the scrap?  Always convert if suspend
  953.                        but only convert on resume if "changed scrap" flag bit is set */
  954.                     if ((!fgApp || (theEvent->message & 0x02)) && pScrapConvert) {
  955.                         (*pScrapConvert)(fgApp);
  956.                     }
  957.                 }
  958.                 else if (flag == 0xfa && fgApp) {
  959.                     SkelCheckCursor (GetWDHandler (frontWindow), evtPt, cursorRgn);
  960.                 }
  961.                 else if (flag == 0xfd) {
  962.                     if (pChildDied) {
  963.                         (*pChildDied) (theEvent);
  964.                     }
  965.                 }
  966.                 else if (pHandleApp4) {
  967.                     (*pHandleApp4) (theEvent);
  968.                 }
  969.             }
  970.             /* fall through to do "idle" processing */
  971.         case nullEvent:
  972.             if (pBkgnd != nil) {
  973.                 (*pBkgnd) ();
  974.             }
  975.             if (!useWaitNextEvent && !PtInRgn (evtPt, cursorRgn)) {
  976.                 SkelCheckCursor (GetWDHandler (frontWindow), theEvent->where, cursorRgn);
  977.             }
  978.             break;
  979. /*
  980.     Mouse click.  Get the window that the click occurred in, and the
  981.     part of the window.
  982. */
  983.         case mouseDown:
  984.         {
  985.             evtPart = FindWindow (evtPt, &evtPort);
  986.             h = GetWHandler (evtPort);
  987. #ifdef supportDialogs
  988.             /* don't allow mouse clicks outside a modal dialog */
  989.             if (evtPort != frontWindow &&
  990.                     (t = GetWDHandler(FrontWindow())) != nil &&
  991.                     (**t).whModal) {
  992.                 break;
  993.             }
  994. #endif
  995.             switch (evtPart)
  996.             {
  997. /*
  998.     Click in a desk accessory window.  Pass back to the system.
  999. */
  1000.                 case inSysWindow:
  1001.                 {
  1002.                     SystemClick (theEvent, evtPort);
  1003.                     break;
  1004.                 }
  1005. /*
  1006.     Click in menu bar.  Track the mouse and execute selected command,
  1007.     if any.
  1008. */
  1009.                 case inMenuBar:
  1010.                 {
  1011.                     DoMenuCommand (MenuSelect (evtPt));
  1012.                     break;
  1013.                 }
  1014. /*
  1015.     Click in grow box.  Resize window.
  1016. */
  1017.                 case inGrow:
  1018.                 {
  1019.                     if (h) {
  1020.                         if ((**h).whCanGrow) {
  1021.                             DoGrow (h, evtPort, evtPt, evtMods);
  1022.                         }
  1023.                         else {
  1024.                             DoMouse (h, theEvent);
  1025.                         }
  1026.                     }
  1027.                     break;
  1028.                 }
  1029. /*
  1030.     Click in title bar.  Drag the window around.  Leave at least
  1031.     4 pixels visible in both directions.
  1032.     Bug fix:  The window is selected first to make sure it's at least
  1033.     activated (unless the command key is down-see Inside Macintosh).
  1034.     DragWindow seems to call StillDown first, so that clicks in drag
  1035.     regions while machine is busy don't otherwise bring window to front if
  1036.     the mouse is already up by the time DragWindow is called.
  1037. */
  1038.                 case inDrag:
  1039.                 {
  1040.                     r = screenPort->portRect;
  1041.                     r.top += mBarHeight;            /* skip down past menu bar */
  1042.                     InsetRect (&r, 4, 4);
  1043.                     SkelDragWindow (evtPort, evtPt, evtMods, &r);
  1044.                     break;
  1045.                 }
  1046. /*
  1047.     Click in close box.  Call the close proc if the window has one.
  1048. */
  1049.                 case inGoAway:
  1050.                 {
  1051.                     if (TrackGoAway (evtPort, evtPt))
  1052.                         DoClose (h);
  1053.                     break;
  1054.                 }
  1055. /*
  1056.     Click in content region.  If the window wasn't frontmost (active),
  1057.     just select it, otherwise pass the click to the window's mouse
  1058.     click handler.
  1059. */
  1060.                 case inContent:
  1061.                 {
  1062.                     if (evtPort != frontWindow) {
  1063.                         SelectWindow (evtPort);
  1064.                         SetPort (evtPort);
  1065.                     }
  1066.                     else
  1067.                         DoMouse (h, theEvent);
  1068.                     break;
  1069.                 }
  1070.  
  1071. /*
  1072.     Click in zoom box.  Track the click and then zoom the window if
  1073.     necessary
  1074. */
  1075.                 case inZoomIn:
  1076.                 case inZoomOut:
  1077.                 {
  1078.                     if(TrackBox(evtPort, evtPt, evtPart))
  1079.                         DoZoom (h, evtPort, evtPart, evtMods);
  1080.                     break;
  1081.                 }
  1082.  
  1083.             }
  1084.             break;    /* mouseDown */
  1085.         }
  1086. /*
  1087.     Key event.  If the command key was down, process as menu item
  1088.     selection, otherwise pass the character and the modifiers flags
  1089.     to the active window's key handler.
  1090.  
  1091.     If dialogs are supported, there's no check for command-key
  1092.     equivalents, since that would have been checked in DoDialog.
  1093. */
  1094.         case keyDown:
  1095.         case autoKey:
  1096.         {
  1097.             evtCode = (theEvent->message & keyCodeMask) >> 8;
  1098.             evtChar = theEvent->message & charCodeMask;
  1099. #ifndef supportDialogs
  1100.             if (evtMods & cmdKey) {
  1101.                 /* try menu equivalent */
  1102.                 DoMenuCommand (MenuKey (evtChar));
  1103.                 break;
  1104.             }
  1105. #endif
  1106.             /* frontWindow is at least frontDocWindow--
  1107.                 tools can't get keys! (Yet!!) */
  1108.             DoKey (GetWHandler (frontWindow), evtChar, evtCode, evtMods);
  1109.             break;
  1110.         }
  1111.  
  1112.         case keyUp:
  1113.         {
  1114.             evtCode = 0x80 | ( (theEvent->message & keyCodeMask) >> 8 );
  1115.             evtChar = theEvent->message & charCodeMask;
  1116.  
  1117.             DoKey (GetWHandler (frontWindow), evtChar, evtCode, evtMods);
  1118.             break;
  1119.         }
  1120.         
  1121. /*
  1122.     Update a window.
  1123. */
  1124.         case updateEvt:
  1125.         {
  1126.             DoUpdate (GetWDHandler ((WindowPtr) theEvent->message));
  1127.             break;
  1128.         }
  1129. /*
  1130.     Activate or deactivate a window.
  1131. */
  1132.         case activateEvt:
  1133.         {
  1134.             DoActivate ((WindowPtr) theEvent->message,
  1135.                         ((theEvent->modifiers & activeFlag) != 0));
  1136.             break;
  1137.         }
  1138. /*
  1139.     handle inserts of uninitialized disks
  1140. */
  1141.         case diskEvt:
  1142.         {
  1143.             if (HiWord (theEvent->message) != noErr) {
  1144.                 DILoad ();
  1145.                 (void) DIBadMount (diskInitPt, theEvent->message);
  1146.                 DIUnload ();
  1147.             }
  1148.             break;
  1149.         }
  1150. /*
  1151.     handle network events
  1152. */
  1153.         case networkEvt:
  1154.         {
  1155.             if (pNetworkProc) {
  1156.                 (*pNetworkProc) (theEvent);
  1157.             }
  1158.             break;
  1159.         }
  1160.     }
  1161. }
  1162.  
  1163.  
  1164. /* -------------------------------------------------------------------- */
  1165. /*                        Interface (public) Routines                        */
  1166. /* -------------------------------------------------------------------- */
  1167.  
  1168.  
  1169. /*
  1170.     Initialize the various Macintosh Managers.
  1171.     Set default upper limits on window sizing.
  1172.     FlushEvents does NOT toss disk insert events, so that disks
  1173.     inserted while the application is starting up don't result
  1174.     in dead drives.
  1175.     Determine whether to use WaitNextEvent or not.
  1176.     Set up big rectangle for cursor management.
  1177. */
  1178. #define _WaitNextEvent 0xA860
  1179.  
  1180. void SkelInit(void (*resume)(), int extra)
  1181. {
  1182.     Rect r;
  1183.  
  1184.     MaxApplZone ();
  1185.     FlushEvents (everyEvent - diskMask, 0 );
  1186. #ifdef applec
  1187.     InitGraf (&qd.thePort);
  1188. #else
  1189.     InitGraf (&thePort);
  1190. #endif
  1191.     InitFonts ();
  1192.     InitWindows ();
  1193.     InitMenus ();
  1194.     TEInit ();
  1195. #ifdef applec
  1196.     InitDialogs ((ResumeProcPtr) resume);        /* no restart proc */
  1197. #else
  1198.     InitDialogs ((ProcPtr) resume);        /* no restart proc */
  1199. #endif
  1200.     InitCursor ();
  1201.  
  1202.     while (extra-- > 0)
  1203.         MoreMasters ();
  1204.  
  1205. /*
  1206.     Set upper limits of window sizing to machine screen size.  Allow
  1207.     for the menu bar (use the glue from the Script Manager).
  1208. */
  1209.     GetWMgrPort (&screenPort);
  1210.     growRect.top = 80;
  1211.     growRect.left = 80;
  1212.     growRect.right = screenPort->portRect.right;
  1213.     growRect.bottom = screenPort->portRect.bottom - (mBarHeight = GetMBarHeight ());
  1214.  
  1215.     /* this is (at this time anyway) pointless */
  1216.     SkelEventMask (eventMask);
  1217.  
  1218.     /* throw away any error return */
  1219.     (void) SysEnvirons (curSysEnvVers, &skelEnvRec);
  1220.     useWaitNextEvent = SkelCheckTrap (_WaitNextEvent, ToolTrap);
  1221.  
  1222.     /* build a region that covers all of the displays available */
  1223.     screensRgn = NewRgn ();
  1224.     SetRect (&r, -32768, -32768, 32767, 32767);
  1225.     /* account for bug in 128K ROMs */
  1226.     if (skelEnvRec.machineType < envMacII)
  1227.         InsetRect (&r, 1, 1);
  1228.     RectRgn (screensRgn, &r);
  1229.     /* a place to watch the cursor in */
  1230.     cursorRgn = NewRgn ();
  1231. }
  1232.  
  1233. /*
  1234.     Main loop.
  1235.  
  1236.     Take care of DA's with SystemTask (not needed with WaitNextEvent).
  1237.     Run background task if there is one. (now at nullEvents in DoEvent)
  1238.     If there is an event, check for an event hook.  If there isn't
  1239.     one defined, or if there is but it returns false, call the
  1240.     general event handler.  (Hook returns true if TransSkel should
  1241.     ignore the event.)
  1242.     If no event, call the "no-event" handler for the front window and for
  1243.     any other windows with idle procedures that are always supposed
  1244.     to run.  This is done in such a way that it is safe for idle procs
  1245.     to remove the handler for their own window if they want (unlikely,
  1246.     but...)  This loop doesn't check whether the window is really
  1247.     a dialog window or not, but it doesn't have to, because such
  1248.     things always have a nil idle proc.
  1249.     
  1250.     doneFlag is reset upon exit.  This allows it to be called
  1251.     repeatedly, or recursively.
  1252.  
  1253.     If dialogs are supported, null events are looked at (in SkelMain)
  1254.     and passed to the event handler.  This is necessary to make sure
  1255.     DialogSelect gets called repeatedly, or the caret won't blink if
  1256.     a dialog has any editText items.
  1257.  
  1258.     In order to be more multi-finder compatible, null-events are passed
  1259.     through to doEvent--where the appropriate idle processing is done.
  1260. */
  1261.  
  1262. Boolean SkelWaitNextEvent(short evtMask, EventRecord *evt, 
  1263.                     long timeOut, RgnHandle checkRgn)
  1264. {
  1265.     if (useWaitNextEvent) {
  1266.         return (WaitNextEvent (evtMask, evt, timeOut, checkRgn));
  1267.     }
  1268.     else {
  1269.         SystemTask ();
  1270.         return (GetNextEvent (evtMask, evt));
  1271.     }
  1272. }
  1273.  
  1274. /*
  1275.     if checkRgn is nil then mouse-moved events *won't* be generated
  1276. */
  1277. void SkelOnePass (RgnHandle checkRgn)
  1278. {
  1279.     EventRecord            theEvent;
  1280.     register WHandler    **wh, **wh2;
  1281.     Boolean                haveEvent;
  1282.     WindowPtr            frontWindow;
  1283.     long                timeOut = pBGTime;
  1284.  
  1285. /*
  1286.     Now watch carefully.  GetNextEvent calls SystemEvent to handle some
  1287.     DA events, and returns false if the event was handled.  However, in
  1288.     such cases the event record will still have the event that occurred,
  1289.     *not* a null event, as you might reasonably expect.  So it's not
  1290.     enough to look at haveEvent.
  1291.  
  1292.     Previous versions figured (wrongly) that haveEvent==false meant a null
  1293.     event had occurred, and passed it through to DoEvent and DoDialog, so
  1294.     that caret-blinking in dialog TextEdit items would occur.  But cmd-key
  1295.     equivalents while DA windows were in front, in particular, allowed
  1296.     already-processed DA events to get into DoEvent (because haveEvent
  1297.     was false), and they got handled twice because when the event record
  1298.     was examined, lo and behold, it had a cmd-key event!  So now this
  1299.     logic is used:
  1300.  
  1301.     If have a real event, and there's no event hook or there is but it
  1302.     doesn't handle the event, OR if the "non-event" is a true nullEvent,
  1303.     then process it. (modified to allow nullEvents to go to event hook)
  1304. */
  1305.         
  1306.     if (fgApp) {
  1307.         timeOut = pFGTime;
  1308.     }
  1309.     haveEvent = SkelWaitNextEvent (eventMask, &theEvent, timeOut, checkRgn);
  1310.  
  1311.     /* ignore haveEvent here so that event hook will get null events
  1312.        a check for a nullEvent is pretty silly in this case */
  1313.     if ((pEvent == nil || (*pEvent)(&theEvent) == false))
  1314.         DoEvent(&theEvent);
  1315.  
  1316. /*
  1317.     Run applicable idle procs.  Make sure to save and restore the port,
  1318.     since idle procs for the non-active window may be run.
  1319. */
  1320.     if (!haveEvent || theEvent.what == nullEvent) {
  1321.         frontWindow = FrontWindow ();
  1322.         for (wh = whList; wh != nil; wh = wh2) {
  1323.             wh2 = (**wh).whNext;
  1324.             if ((**wh).whWind == frontWindow || !(**wh).whFrontOnly) {
  1325.                 DoIdle (wh);
  1326.             }
  1327.         }
  1328.     }
  1329. }
  1330.  
  1331. void SkelMain ()
  1332. {
  1333. #ifdef    CHECK_STACK
  1334.     long stackFree;
  1335. #endif
  1336.     /* create a region to do cursor handling in */
  1337.     while (!doneFlag) {    
  1338.         SkelOnePass (cursorRgn);
  1339. #ifdef    CHECK_STACK
  1340.         stackFree = StackSpace ();
  1341. #endif
  1342.     }
  1343.     doneFlag = false;
  1344.     /* ditch the cursor control region */
  1345. }
  1346.  
  1347.  
  1348. /*
  1349.     Tell SkelMain to stop
  1350. */
  1351.  
  1352. void SkelWhoa ()
  1353. {
  1354.     doneFlag = true;
  1355. }
  1356.  
  1357.  
  1358. /*
  1359.     Clobber all the menu, window and dialog handlers
  1360. */
  1361.  
  1362. void SkelClobber ()
  1363. {
  1364.     while (whList != nil)
  1365.         SkelRmveWind ((**whList).whWind);
  1366.  
  1367.     /* 'false' removes the annoying flicker as menus are deleted */
  1368.     while (mhList != nil)
  1369.         RemoveMenu (GetMHandle((**mhList).mhID), false);
  1370.     /* draw the menu bar (now empty) in case there's some system level cleanup */
  1371.     DrawMenuBar ();
  1372.     DisposeRgn (cursorRgn);
  1373.     /* make the event mask innocuous for uniFinder */
  1374.     SetEventMask (everyEvent ^ keyUpMask);
  1375. }
  1376.  
  1377.  
  1378. /* -------------------------------------------------------------------- */
  1379. /*                        Menu-handler interface routines                    */
  1380. /* -------------------------------------------------------------------- */
  1381.  
  1382.  
  1383. /*
  1384.     Install handler for a menu.  Remove any previous handler for it.
  1385.     Pass the following parameters:
  1386.  
  1387.     theMenu    Handle to the menu to be handled.  Must be created by host.
  1388.     pSelect    Proc that handles selection of items from menu.  If this is
  1389.             nil, the menu is installed, but nothing happens when items
  1390.             are selected from it.
  1391.     pClobber Proc for disposal of handler's data structures.  Usually
  1392.             nil for menus that remain in menu bar until program
  1393.             termination.
  1394.     isPull    Should this be installed in the menubar?
  1395.     drawBar    draw the menu bar?
  1396. */
  1397.  
  1398. void SkelMenu(MenuHandle theMenu, 
  1399.     void (*pSelect)(short), 
  1400.     void (*pClobber)(MenuHandle), 
  1401.     Boolean isPull, 
  1402.     Boolean drawBar)
  1403. {
  1404.     register MHandler    **mh;
  1405.  
  1406.     mhClobOnRmve = false;
  1407.     SkelRmveMenu (theMenu);
  1408.     mhClobOnRmve = true;
  1409.  
  1410.     mh = New (MHandler);
  1411.     (**mh).mhNext = mhList;
  1412.     mhList = mh;
  1413.     (**mh).mhID = (**theMenu).menuID;            /* get menu id number */
  1414.     (**mh).mhSelect = pSelect;                    /* install selection handler */
  1415.     (**mh).mhClobber = pClobber;                /* install disposal handler */
  1416.     InsertMenu (theMenu, (isPull) ? -1 : 0);    /* insert menu in menulist */
  1417.     if (drawBar)
  1418.         DrawMenuBar ();
  1419. }
  1420.  
  1421. /*
  1422.     Remove a menu from the menu list for the user
  1423. */
  1424.  
  1425. void SkelRmveMenu (MenuHandle theMenu)
  1426. {
  1427.     /* 'true' forces the menubar to be redrawn */
  1428.     RemoveMenu (theMenu, true);
  1429. }
  1430.  
  1431. /*
  1432.     Install a handler for the Apple menu.
  1433.     
  1434.     SkelApple is called if TransSkel is supposed to handle the apple
  1435.     menu itself.  aboutTitle is the title of the first item.  If nil,
  1436.     then only desk accessories are put into the menu.  If not nil, then
  1437.     the title is entered as the first item, followed by a gray line,
  1438.     then the desk accessories.
  1439.  
  1440.     SkelApple does not cause the menubar to be drawn, so if the Apple
  1441.     menu is the only menu, DrawMenuBar must be called afterward.
  1442.  
  1443.     No value is returned, unlike SkelMenu.  It is assumed that SkelApple
  1444.     will be called so early in the application that the call the SkelMenu
  1445.     is virtually certain to succeed.  If it doesn't, there's probably
  1446.     little hope for the application anyway.
  1447. */
  1448.  
  1449. void SkelApple(char *aboutTitle, void (*aboutProc)(void))
  1450. {
  1451.     appleID = 1;
  1452.     appleMenu = NewMenu (appleID, "\p\024");    /* 024 = apple character */
  1453.     if (aboutTitle != nil) 
  1454.     {
  1455.         doAbout = true;
  1456.         AppendMenu (appleMenu, aboutTitle);    /* add About... item title */
  1457.         AppendMenu (appleMenu, "\p(-");        /* add gray line */
  1458.         appleAboutProc = aboutProc;
  1459.     }
  1460.     AddResMenu (appleMenu, 'DRVR');        /* add desk accessories */
  1461.     SkelMenu (appleMenu, DoAppleItem, DoAppleClobber, false, false);
  1462. }
  1463.  
  1464. void SkelHelp(char *helpTitle, void (*helpProc)(void))
  1465. {
  1466.     if (appleID == 1 && helpTitle != nil) {
  1467.         doHelp = true;
  1468.         InsMenuItem (appleMenu, helpTitle, (doAbout) ? 1 : 0);
  1469.         appleHelpProc = helpProc;
  1470.     }
  1471. }
  1472.  
  1473. void SkelEnableMenu(short mID, Boolean redraw)
  1474. {
  1475.     MenuHandle m = GetMHandle (mID);
  1476.     if (m) {
  1477.         EnableItem (m, 0);
  1478.     }
  1479.     if (redraw)
  1480.         DrawMenuBar ();
  1481. }
  1482.  
  1483. void SkelDisableMenu (short mID, Boolean redraw)
  1484. {
  1485.     MenuHandle m = GetMHandle (mID);
  1486.     if (m) 
  1487.     {
  1488.         DisableItem (m, 0);
  1489.     }
  1490.     if (redraw)
  1491.         DrawMenuBar ();
  1492. }
  1493.  
  1494. void SkelEnableMenus ()
  1495. {
  1496.     register MHandler **mh = mhList;
  1497.     while (mh) {
  1498.         SkelEnableMenu ((**mh).mhID, false);
  1499.         mh = (**mh).mhNext;
  1500.     }
  1501.     DrawMenuBar ();
  1502. }
  1503.  
  1504. void SkelDisableMenus ()
  1505. {
  1506.     register MHandler **mh = mhList;
  1507.     while (mh) {
  1508.         SkelDisableMenu ((**mh).mhID, false);
  1509.         mh = (**mh).mhNext;
  1510.     }
  1511.     DrawMenuBar ();
  1512. }
  1513.  
  1514. /* -------------------------------------------------------------------- */
  1515. /*                    Window-handler interface routines                    */
  1516. /* -------------------------------------------------------------------- */
  1517.  
  1518. /*
  1519.     Install handler for a window.  Remove any previous handler for it.
  1520.     Pass the following parameters:
  1521.  
  1522.     theWind    Pointer to the window to be handled.  Must be created by host.
  1523.     pMouse    Proc to handle mouse clicks in window.  The proc will be
  1524.             passed the point (in local coordinates), the time of the
  1525.             click, and the modifier flags word.
  1526.     pKey    Proc to handle key clicks in window.  The proc will be passed
  1527.             the character and the modifier flags word.
  1528.     pUpdate    Proc for updating window.  TransSkel brackets calls to update
  1529.             procs with calls to BeginUpdate and EndUpdate, so the visRgn
  1530.             is set up correctly.  A flag is passed indicating whether the
  1531.             window was resized or not.  BY CONVENTION, the entire portRect
  1532.             is invalidated when the window is resized.  That way, the
  1533.             handler's update proc can redraw the entire content region
  1534.             without interference from BeginUpdate/EndUpdate.  The flag
  1535.             is set to false after the update proc is called; the
  1536.             assumption is made that it will notice the resizing and
  1537.             respond appropriately.
  1538.     pActivate Proc to execute when window is activated or deactivated.
  1539.             A boolean is passed to it which is true if the window is
  1540.             coming active, false if it's going inactive.
  1541.     pClose    Proc to execute when mouse clicked in close box.  Useful
  1542.             mainly to temp window handlers that want to know when to
  1543.             self-destruct (with SkelRmveWind).
  1544.     pClobber Proc for disposal of handler's data structures
  1545.     pIdle    Proc to execute when no events are pending.
  1546.     frontOnly True if pIdle should execute on no events only when
  1547.             theWind is frontmost, false if executes all the time.  Note
  1548.             that if it always goes, everything else may be slowed down!
  1549.  
  1550.     If a particular procedure is not needed (e.g., key events are
  1551.     not processed by a handler), pass nil in place of the appropriate
  1552.     procedure address.
  1553.  
  1554.     All handler procedures may assume that the port is set correctly
  1555.     at the time they are called.
  1556. */
  1557.  
  1558. Boolean SkelWindow(
  1559.     WindowPtr theWind, 
  1560.     void (*pMouse)(Point,long,short),
  1561.     void (*pKey)(char,unsigned char,short),
  1562.     void (*pUpdate)(Boolean,short), 
  1563.     void (*pActivate)(Boolean),
  1564.     void (*pClose)(void), 
  1565.     void (*pClobber)(void), 
  1566.     void (*pIdle)(void), 
  1567.     Boolean frontOnly)
  1568. {
  1569.     register WHandler    **hHand, *hPtr;
  1570.  
  1571.     if ((hHand = GetWDHandler (theWind)) != nil) {
  1572.         /* remove the window, don't clobber it! */
  1573.         whClobOnRmve = false;
  1574.         SkelRmveWind (theWind);
  1575.         whClobOnRmve = true;
  1576.     }
  1577. /*
  1578.     Get new handler, attach to list of handlers.  It is attached to the
  1579.     beginning of the list, which is simpler; the order is presumably
  1580.     irrelevant to the host, anyway.
  1581. */
  1582.     hHand = SkelNullHandler (theWind);
  1583.     if (hHand) {
  1584. /*
  1585.     Fill in handler fields
  1586. */
  1587.         hPtr = *hHand;
  1588.         hPtr->whMouse = pMouse;
  1589.         hPtr->whKey = pKey;
  1590.         hPtr->whUpdate = pUpdate;
  1591.         hPtr->whActivate = pActivate;
  1592.         hPtr->whClose = pClose;
  1593.         hPtr->whClobber = pClobber;
  1594.         hPtr->whIdle = pIdle;
  1595.         hPtr->whFrontOnly = frontOnly;
  1596.         hPtr->whSized = false;
  1597.         hPtr->whSizedMods = 0;
  1598.     }
  1599.     return (hHand != nil);
  1600. }
  1601.  
  1602.  
  1603. /*
  1604.     Remove a window handler.  This calls the handler's disposal routine
  1605.     and then takes the handler out of the handler list and disposes
  1606.     of it.
  1607.  
  1608.     SkelRmveWind is also called by SkelRmveDlog.
  1609. */
  1610.  
  1611. void SkelRmveWind (WindowPtr theWind)
  1612. {
  1613. register WHandler    **h, **h2;
  1614.  
  1615.     if (whList != nil) {
  1616.         /* if list empty, ignore */
  1617.         if ((**whList).whWind == theWind) 
  1618.         {
  1619.             /* is it the first element? */
  1620.             h2 = whList;
  1621.             whList = (**whList).whNext;
  1622.         }
  1623.         else {
  1624.             for (h = whList; h != nil; h = h2) 
  1625.             {
  1626.                 h2 = (**h).whNext;
  1627.                 if (h2 == nil) {
  1628.                     /* theWind not in list! */
  1629.                     return;
  1630.                 }
  1631.                 if ((**h2).whWind == theWind) 
  1632.                 {
  1633.                     /* found it */
  1634.                     (**h).whNext = (**h2).whNext;
  1635.                     break;
  1636.                 }
  1637.             }
  1638.         }
  1639.         if (whClobOnRmve)
  1640.             DoClobber (h2);                /* call disposal routine */
  1641.         if ((**h2).whCursorRgn) 
  1642.         {
  1643.             DisposeRgn ((**h2).whCursorRgn);
  1644.         }
  1645.         DisposHandle ((Handle) h2);        /* get rid of handler record */
  1646.     }
  1647. }
  1648.  
  1649. /*
  1650.     Set a cursor and a region to allow WaitNextEvent to return mouse-moved
  1651.     events.  This routine should probably also allow a routine to be passed
  1652.     in that would be called when the cursor changed—allowing multiple regions
  1653.     (and multiple cursors) per window, or perhaps a list of regions and
  1654.     cursors.  At the moment the most economical and useful way of doing this
  1655.     is unclear.  -RTS
  1656. */
  1657.  
  1658. void SkelSetCursor(WindowPtr theWind, CursHandle theCursor, RgnHandle theCursorRgn)
  1659. {
  1660.     register WHandler        **h;
  1661.     if ((h = GetWDHandler (theWind)) != nil) 
  1662.     {
  1663.         if ((**h).whHaveCursor = (theCursorRgn != nil)) 
  1664.         {
  1665.             if (!(**h).whCursorRgn) 
  1666.             {
  1667.                 (**h).whCursorRgn = NewRgn ();
  1668.             }
  1669.             CopyRgn (theCursorRgn, (**h).whCursorRgn);
  1670.         }
  1671.         else {
  1672.             if ((**h).whCursorRgn) 
  1673.             {
  1674.                 DisposeRgn ((**h).whCursorRgn);
  1675.             }
  1676.             (**h).whCursorRgn = theCursorRgn;
  1677.         }
  1678.         (**h).whCursor = theCursor;
  1679.     }
  1680. }
  1681.  
  1682. /*
  1683.     Return something about the state of cursor management for this
  1684.     window.  Allows the resize code to do something like:
  1685.     
  1686.     if (SkelGetCursor (nowWin, &cursorHand, &cursorRgn)) {
  1687.         cursorRgn = calcUpdatedCursorRegion (nowWin);
  1688.         SkelSetCursor (nowWin, cursorHand, cursorRgn);
  1689.     }
  1690. */
  1691.  
  1692. Boolean SkelGetCursor(WindowPtr theWind, CursHandle *theCursor, 
  1693.                     RgnHandle *theCursorRgn)
  1694. {
  1695.     register WHandler **h;
  1696.     if ((h = GetWDHandler (theWind)) != nil) 
  1697.     {
  1698.         *theCursor = (**h).whCursor;
  1699.         *theCursorRgn = (**h).whCursorRgn;
  1700.         return ((**h).whHaveCursor);
  1701.     }
  1702.     else 
  1703.         {
  1704.             return (false);
  1705.     }
  1706. }
  1707.  
  1708. /*
  1709.     allow the user to associate an arbitrary long integer with
  1710.     a window
  1711. */
  1712.  
  1713. void SkelSetReference(WindowPtr theWind, long refCon)
  1714. {
  1715.     register WHandler **h;
  1716.     if ((h = GetWDHandler (theWind)) != nil) {
  1717.         (**h).userReference = refCon;
  1718.     }
  1719. }
  1720.  
  1721. long SkelGetReference(WindowPtr theWind)
  1722. {
  1723.     register WHandler **h;
  1724.     if ((h = GetWDHandler (theWind)) != nil) {
  1725.         return ((**h).userReference);
  1726.     }
  1727.     else {
  1728.         return (0L);
  1729.     }
  1730. }
  1731.  
  1732. #ifdef    supportDialogs
  1733.  
  1734. /* -------------------------------------------------------------------- */
  1735. /*                    Dialog-handler interface routines                    */
  1736. /* -------------------------------------------------------------------- */
  1737.  
  1738. /*
  1739.     Install a dialog handler.  Remove any previous handler for it.
  1740.     SkelDialog calls SkelWindow as a subsidiary to install a window
  1741.     handler, then sets the event procedure on return.
  1742.  
  1743.     Pass the following parameters:
  1744.  
  1745.     theDialog    Pointer to the dialog to be handled.  Must be created
  1746.             by host.
  1747.     pEvent    Event-handling proc for dialog events.
  1748.     pClose    Proc to execute when mouse clicked in close box.  Useful
  1749.             mainly to dialog handlers that want to know when to
  1750.             self-destruct (with SkelRmveDlog).
  1751.     pClobber Proc for disposal of handler's data structures
  1752.  
  1753.     If a particular procedure is not needed, pass nil in place of
  1754.     the appropriate procedure address.
  1755.  
  1756.     All handler procedures may assume that the port is set correctly
  1757.     at the time they are called.
  1758. */
  1759.  
  1760. static void SkelDefaultDialogUpdate (Boolean resized, short mods)
  1761. {
  1762. #ifdef applec
  1763. #pragma unused (resized, mods)
  1764. #endif
  1765.     DialogPtr dLog;
  1766.     GetPort ((WindowPtr *) &dLog);
  1767.     UpdtDialog(dLog, dLog->visRgn);
  1768. }
  1769.  
  1770. void SkelDialog(DialogPtr theDialog, 
  1771.     Boolean (*pEvent)(short *, EventRecord *), 
  1772.     Boolean (*pCheck)(short), 
  1773.     Boolean (*pKeys)(short *, EventRecord *), 
  1774.     void (*pUpdate)(Boolean,short), 
  1775.     void (*pClose)(void), 
  1776.     void (*pClobber)(void))
  1777. {
  1778.     register WHandler **h;
  1779.     if (pUpdate == nil)
  1780.         pUpdate = SkelDefaultDialogUpdate;
  1781. #ifdef applec
  1782.     SkelWindow (theDialog, nil,
  1783.                 (void (*)(char, unsigned char, short)) pKeys,
  1784.                 pUpdate, nil, pClose, pClobber,
  1785.                 nil, false);
  1786. #else
  1787.     SkelWindow (theDialog, nil,
  1788.                 (void (*)())pKeys,
  1789.                 pUpdate, nil, pClose, pClobber,
  1790.                 nil, false);
  1791. #endif
  1792.     h = GetWDHandler (theDialog);
  1793.     (**h).whEvent = pEvent;
  1794.     (**h).whCheck = pCheck;
  1795. }
  1796.  
  1797. /*
  1798.     Remove a dialog and its handler
  1799. */
  1800.  
  1801. void SkelRmveDlog (DialogPtr theDialog)
  1802. {
  1803.     SkelRmveWind (theDialog);
  1804. }
  1805.  
  1806. /*
  1807.     Act like modal dialog--but do all the other stuff, too
  1808. */
  1809.  
  1810. short SkelModalDialog(
  1811.     DialogPtr dLog, 
  1812.     Boolean (*pEvent)(short *, EventRecord *), 
  1813.     Boolean (*pCheck)(short), 
  1814.     Boolean (*pKeys)(short *, EventRecord *), 
  1815.     void (*pUpdate)(Boolean,short), 
  1816.     long refCon);
  1817. {
  1818.     register WHandler **h;
  1819.     short itemHit;
  1820.  
  1821.     SkelDialog (dLog, pEvent, pCheck, pKeys, pUpdate, nil, nil);
  1822.     h = GetDHandler (dLog);
  1823.     SkelSetReference (dLog, refCon);
  1824.     (**h).whModal = true;
  1825.     /* default to 0 for check routine */
  1826.     (**h).whItemHit = 0;
  1827.     while (pCheck && (*pCheck) ((**h).whItemHit)) {
  1828.         (**h).whItemHit = 0;
  1829.         SkelOnePass (0);
  1830.         /* in case this got changed by the main loop */
  1831.         SetPort ((GrafPtr) dLog);
  1832.     }
  1833.     itemHit = (**h).whItemHit;
  1834.     SkelRmveDlog (dLog);
  1835.     return (itemHit);
  1836. }
  1837. #endif
  1838.  
  1839.  
  1840. /* -------------------------------------------------------------------- */
  1841. /*                    Miscellaneous interface routines                    */
  1842. /* -------------------------------------------------------------------- */
  1843.  
  1844. /*
  1845.     Override the default sizing limits for a window, or, if theWind
  1846.     is nil, reset the default limits used by SkelWindow.
  1847. */
  1848.  
  1849. void SkelGrowBounds(WindowPtr theWind, short hLo, short vLo, short hHi, short vHi)
  1850. {
  1851.     register WHandler    **h;
  1852.     Rect                r;
  1853.  
  1854.     if (theWind == nil) {
  1855.         SetRect (&growRect, hLo, vLo, hHi, vHi);
  1856.     }
  1857.     else if ((h = GetWDHandler (theWind)) != nil) {
  1858.         SetRect (&r, hLo, vLo, hHi, vHi);
  1859.         (**h).whGrow = r;
  1860.         (**h).whCanGrow = ((hLo != hHi) || (vLo != vHi));
  1861.     }
  1862. }
  1863.  
  1864.  
  1865. /*
  1866.     Set the event mask.  Allow keyup events. -DTH
  1867. */
  1868.  
  1869. void SkelEventMask (short mask)
  1870. {
  1871.     eventMask = mask;
  1872.     if (everyEvent == (eventMask | keyUpMask))
  1873.         SetEventMask (eventMask);
  1874. }
  1875.  
  1876.  
  1877. /*
  1878.     Return the event mask.
  1879. */
  1880.  
  1881. void SkelGetEventMask (short *mask)
  1882. {
  1883.     *mask = eventMask;
  1884. }
  1885.  
  1886.  
  1887. /*
  1888.     Install a background task.  If p is nil, the current task is
  1889.     disabled.  fgTime and bgTime are the timeOut values when
  1890.     WaitNextEvent is being used. -RTS
  1891. */
  1892.  
  1893. void SkelBackground(void (*p)(void), long fgTime, long bgTime)
  1894. {
  1895.     pBkgnd = p;
  1896.     pFGTime = fgTime;
  1897.     pBGTime = bgTime;
  1898. }
  1899.  
  1900.  
  1901. /*
  1902.     Return the current background task.  Return nil if none.
  1903.     Also return the current foreground and background pause times
  1904.     for use with WaitNextEvent.
  1905. */
  1906.  
  1907. void SkelGetBackground(void (**p)(void), long *fgTime, long *bgTime)
  1908. {
  1909.     *p = pBkgnd;
  1910.     *fgTime = pFGTime;
  1911.     *bgTime = pBGTime;
  1912. }
  1913.  
  1914.  
  1915. /*
  1916.     Install an event-inspecting hook.  If p is nil, the hook is
  1917.     disabled.
  1918. */
  1919.  
  1920. void SkelEventHook(Boolean (*p)(EventRecord *))
  1921. {
  1922.     pEvent = p;
  1923. }
  1924.  
  1925.  
  1926. /*
  1927.     Return the current event-inspecting hook.  Return nil if none.
  1928. */
  1929.  
  1930. void SkelGetEventHook(Boolean (**p)(EventRecord *))
  1931. {
  1932.     *p = pEvent;
  1933. }
  1934.  
  1935. /*
  1936.     Install a scrap conversion hook.  If p is nil, the hook is disabled.
  1937. */
  1938.  
  1939. void SkelScrapConvert(void (*p)(Boolean))
  1940. {
  1941.     pScrapConvert = p;
  1942. }
  1943.  
  1944. /*
  1945.     Return the current scrap conversion hook.  Return nil if none.
  1946. */
  1947.  
  1948. void SkelGetScrapConvert(void (**p)(Boolean))
  1949. {
  1950.     *p = pScrapConvert;
  1951. }
  1952.  
  1953. /*
  1954.     Install a multifinder suspend